package com.jargonee.threads;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;

import org.apache.http.client.ClientProtocolException;
import org.json.JSONException;
import org.json.JSONObject;

import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import com.jargonee.utils.JargoneeUtils;

/**
 * Thread responsible for setting up and making all requests to backend
 * 
 * @author potlow
 * 
 */
public class BackendThread extends Thread {

	public enum BackendThreadModes { RetrieveCurrentAddress , RetrieveLocalResults, SubmitDefinition };
	
	public enum BackendThreadMessages { SearchSuccessful, TroubleGettingResults, NoResultsFound, SubmitSuccessful,
		TroubleGettingLocation, LocationFound, NoLocationService, BadInternetConnection, TroubleSubmittingDefinition }

	// mode in which the thread should function in
	private BackendThreadModes mode;

	// Handler for communicating back with regular thread
	private Handler handler;

	// Bundle for obtaining extra parameter
	private Map<String, Object> extraParams;

	public BackendThread(Handler handler, BackendThreadModes mode, Map<String, Object> extraParams) {
		this.extraParams = extraParams;
		this.mode = mode;
		this.handler = handler;
	}

	@Override
	public void run() {

		switch (this.mode) {
		case RetrieveCurrentAddress:
			retrieveCurrentAddress();
			break;
		case RetrieveLocalResults:
			retrieveLocalResults();
			break;
		case SubmitDefinition:
			submitDefiniton();
		default:
			break;
		}

	}

	/**
	 * Gets address of current location
	 */
	private void retrieveCurrentAddress() {

		// get location and geocoder
		LocationManager locationManager = (LocationManager) extraParams.get("locationManager");
		Geocoder geocoder = (Geocoder) extraParams.get("geocoder");

		// get location
		//String bestProvider = locationManager.getBestProvider(new Criteria(), true);
		String bestProvider = "test";
		if (bestProvider == null) {
			Message msg = handler.obtainMessage();
			Bundle bundle = new Bundle();
			bundle.putString("message", "Location Services must be enabled to get best results");
			bundle.putSerializable("message type", BackendThreadMessages.NoLocationService);
			msg.setData(bundle);
			handler.sendMessage(msg);
			return;
		}
		//Location location = locationManager.getLastKnownLocation(bestProvider);
		Location location = new Location("test");
		location.setLatitude(new Double("37.422006"));
		location.setLongitude(new Double("-122.084095"));
		location.setTime(System.currentTimeMillis());
		if (location == null) {
			Message msg = handler.obtainMessage();
			Bundle bundle = new Bundle();
			bundle.putString("message", "Trouble getting current location. Try Again.");
			bundle.putSerializable("message type", BackendThreadMessages.NoLocationService);
			msg.setData(bundle);
			handler.sendMessage(msg);
			return;
		}

		// get address
		Address address = null;
		try {
			address = JargoneeUtils.getAddressFromLocationWithGeocoder(location, geocoder);
		} catch (IOException ioe) {
			Message msg = handler.obtainMessage();
			Bundle bundle = new Bundle();
			bundle.putString("message", "Trouble getting current location. Please try again");
			bundle.putSerializable("message type", BackendThreadMessages.TroubleGettingLocation);
			msg.setData(bundle);
			handler.sendMessage(msg);
			return;
		} catch (JSONException je) {
			Message msg = handler.obtainMessage();
			Bundle bundle = new Bundle();
			bundle.putString("message", "Trouble getting current location. Please try again");
			bundle.putSerializable("message type", BackendThreadMessages.TroubleGettingLocation);
			msg.setData(bundle);
			handler.sendMessage(msg);
			return;
		}
		
		Bundle bundle = new Bundle();
		bundle.putSerializable("message type", BackendThreadMessages.LocationFound);
		Message toMain = handler.obtainMessage();
		toMain.obj = address;
		toMain.setData(bundle);
		handler.sendMessage(toMain);
	}
		
	/**
	 * Get local results of buzzword
	 */
	private void retrieveLocalResults() {
		
		// get Uri Builder, and url parameters
		Uri.Builder uriBuilder = (Uri.Builder)extraParams.get("uriBuilder");
		String distance = (String)extraParams.get("distance");
		String word = (String)extraParams.get("word");
		Address address = (Address)extraParams.get("address");

		// form url
		uriBuilder = uriBuilder.appendQueryParameter("distance", distance);
		uriBuilder = uriBuilder.appendQueryParameter("word", word);
		String area = address.getSubAdminArea() + "," + address.getAdminArea() + "," + address.getCountryName();
		uriBuilder = uriBuilder.appendQueryParameter("area", area);
		
		JSONObject jsonObject;
		try {
			String jsonString = JargoneeUtils.getResponseFromUri(uriBuilder);
			jsonObject = new JSONObject(jsonString);
		} catch (IOException ioe) {
			Message msg = handler.obtainMessage();
			Bundle bundle = new Bundle();
			bundle.putString("message", "Trouble getting search results. Please try again");
			bundle.putSerializable("message type", BackendThreadMessages.TroubleGettingResults);
			msg.setData(bundle);
			handler.sendMessage(msg);
			return;
		} catch (JSONException je) {
			Message msg = handler.obtainMessage();
			Bundle bundle = new Bundle();
			bundle.putString("message", "Trouble getting search results. Please try again");
			bundle.putSerializable("message type", BackendThreadMessages.TroubleGettingResults);
			msg.setData(bundle);
			handler.sendMessage(msg);
			return;
		}
		
		if(jsonObject.optInt("count") == 0) {
			Message msg = handler.obtainMessage();
			Bundle bundle = new Bundle();
			bundle.putString("message", "No results found.");
			bundle.putSerializable("message type", BackendThreadMessages.NoResultsFound);
			msg.setData(bundle);
			handler.sendMessage(msg);
			return;
		}
			
		Message toMain = handler.obtainMessage();
		Bundle bundle = new Bundle();
		bundle.putSerializable("message type", BackendThreadMessages.SearchSuccessful);
		toMain.setData(bundle);
		toMain.obj = jsonObject;
		handler.sendMessage(toMain);
	}

	private void submitDefiniton() {
		// get Uri Builder, and url parameters
		Uri.Builder uriBuilder = (Uri.Builder)extraParams.get("uriBuilder");
		String json = (String)extraParams.get("json");
		
		try {
			String jsonString = JargoneeUtils.postBodyToUri(uriBuilder, json);
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}
